﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MetroLightKit.Helpers
{
    public static class UiHelper
    {
        public static TObject FindVisualParent<TObject>(UIElement child) where TObject : UIElement
        {
            if (child == null)
            {
                return null;
            }

            var parent = VisualTreeHelper.GetParent(child) as UIElement;

            while (parent != null)
            {
                var found = parent as TObject;
                if (found != null)
                {
                    return found;
                }
                else
                {
                    parent = VisualTreeHelper.GetParent(parent) as UIElement;
                }
            }

            return null;
        }

        public static IEnumerable<DependencyObject> Ancestors(this DependencyObject root)
        {
            DependencyObject current = VisualTreeHelper.GetParent(root);
            while (current != null)
            {
                yield return current;
                current = VisualTreeHelper.GetParent(current);
            }
        }

        public static TChildItem FindVisualChild<TChildItem>(this DependencyObject obj)
            where TChildItem : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                if (child != null && child is TChildItem)
                    return (TChildItem) child;
                else
                {
                    var childOfChild = FindVisualChild<TChildItem>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }

            return null;
        }

        public static IEnumerable<TChildItem> FindVisualChilds<TChildItem>(this DependencyObject obj)
            where TChildItem : DependencyObject
        {
            var visible = (Visibility) obj.GetValue(UIElement.VisibilityProperty);
            if (visible == Visibility.Visible)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                    if (child != null && child is TChildItem)
                        yield return (TChildItem) child;
                    else
                    {
                        foreach (TChildItem item in FindVisualChilds<TChildItem>(child))
                            yield return item;
                    }
                }
            }
        }


        public static IEnumerable<TChildItem> FindChilds<TChildItem>(this DependencyObject obj)
            where TChildItem : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                if (child != null && child is TChildItem)
                    yield return (TChildItem) child;
                else
                {
                    foreach (TChildItem item in FindChilds<TChildItem>(child))
                        yield return item;
                }
            }
        }


        //public static T FindNextUIElementInItemContenair<T>(this DependencyObject obj) where T : DependencyObject
        //{

        //    ContentPresenter monItem = UIHelper.FindVisualParent<ContentPresenter>(obj as UIElement);
        //    ItemsControl objItemControl = UIHelper.FindVisualParent<ItemsControl>(obj as UIElement);
        //    IEnumerable<DependencyObject> DependencyObjectCollection = objItemControl.GetContainers();

        //    int tbIndex = 0;
        //    object obIndex = obj.GetValue(System.Windows.Controls.Control.TabIndexProperty);
        //    if (obIndex is int)
        //        tbIndex = (int)obIndex;

        //    bool itemIsFind = false;
        //    foreach (ContentPresenter item in DependencyObjectCollection)
        //    {
        //        ContentPresenter UIClassPresenter = (ContentPresenter)item;
        //        if (!itemIsFind)
        //        {
        //            if (monItem == UIClassPresenter)
        //                itemIsFind = true;
        //            else
        //                continue;
        //        }

        //        foreach (T uielm in UIClassPresenter.FindVisualChilds<T>())
        //        {
        //            if (uielm != obj)
        //            {
        //                if (uielm is FrameworkElement)
        //                {
        //                    Visibility vobj = (Visibility)uielm.GetValue(System.Windows.UIElement.VisibilityProperty);
        //                    bool eobj = (bool)uielm.GetValue(System.Windows.Controls.Control.IsEnabledProperty);
        //                    if (vobj != Visibility.Collapsed && eobj == true)
        //                    {
        //                        object obIndex2 = uielm.GetValue(System.Windows.Controls.Control.TabIndexProperty);
        //                        if (obIndex2 is int)
        //                        {
        //                            if ((int)obIndex2 >= tbIndex && (int)obIndex2 < 2000 && (int)obIndex2 > 0)
        //                                return uielm;
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //        tbIndex = 1;
        //    }

        //    ContentPresenter monItem1 = UIHelper.FindVisualParent<ContentPresenter>(objItemControl as UIElement);
        //    ItemsControl parentObjItemControl = UIHelper.FindVisualParent<ItemsControl>(objItemControl as UIElement);
        //    IEnumerable<DependencyObject> DependencyObjectCollection2 = parentObjItemControl.GetContainers(); //strubriques
        //    bool find2 = false;
        //    foreach (ContentPresenter item in DependencyObjectCollection2)
        //    {
        //        ContentPresenter UIClassPresenter1 = (ContentPresenter)item;
        //        if (!find2)
        //        {
        //            if (monItem1 == UIClassPresenter1)
        //                find2 = true;
        //            continue;
        //        }
        //        foreach (T uielm in UIClassPresenter1.FindVisualChilds<T>())
        //        {
        //            if (uielm is FrameworkElement)
        //            {
        //                Visibility vobj = (Visibility)uielm.GetValue(System.Windows.UIElement.VisibilityProperty);
        //                bool eobj = (bool)uielm.GetValue(System.Windows.Controls.Control.IsEnabledProperty);
        //                if (vobj != Visibility.Collapsed && eobj == true)
        //                {
        //                    object obIndex2 = uielm.GetValue(System.Windows.Controls.Control.TabIndexProperty);
        //                    if (obIndex2 is int)
        //                    {
        //                        if ((int)obIndex2 < 2000 && (int)obIndex2 > 0)
        //                            return uielm;
        //                    }
        //                }
        //            }
        //        }
        //    }
        //    return null;
        //}


        //

        //public static bool FocusOnFirstFocusableChild(DependencyObject rootObject)
        //{
        //    return FocusOnFirstFocusableChild(rootObject, false);
        //}

        //public static bool FocusOnFirstFocusableChild(DependencyObject rootObject, bool skipSelf)
        //{
        //    Func<Control, bool> predicate = null;
        //    if (rootObject != null)
        //    {
        //        if (predicate == null)
        //        {
        //            predicate = delegate(Control ctl)
        //            {
        //                if (skipSelf)
        //                {
        //                    if (rootObject == ctl)
        //                    {
        //                        return false;
        //                    }
        //                    skipSelf = false;
        //                }
        //                return ctl.IsTabStop && (Visibility.Visible == ctl.Visibility);
        //            };
        //        }
        //        Control control = rootObject.FindVisualChildByType<Control>(predicate);
        //        if (control != null)
        //        {
        //            return control.Focus();
        //        }
        //    }
        //    return false;
        //}

        //public static bool FocusOnFirstTabStoppableChild(DependencyObject rootObject)
        //{
        //    return FocusOnFirstTabStoppableChild(rootObject, false);
        //}

        //public static bool FocusOnFirstTabStoppableChild(DependencyObject rootObject, bool skipSelf)
        //{
        //    return FocusOnFirstTabStoppableChild(rootObject, skipSelf, null);
        //}

        //public static bool FocusOnFirstTabStoppableChild(DependencyObject rootObject, Control waitUntilControl)
        //{
        //    return FocusOnFirstTabStoppableChild(rootObject, false, waitUntilControl);
        //}

        //public static bool FocusOnFirstTabStoppableChild(DependencyObject rootObject, bool skipSelf, Control waitUntilControl)
        //{
        //    Func<Control, bool> predicate = null;
        //    if (rootObject != null)
        //    {
        //        if (predicate == null)
        //        {
        //            predicate = delegate(Control dp)
        //            {
        //                if (skipSelf)
        //                {
        //                    if (rootObject == dp)
        //                    {
        //                        return false;
        //                    }
        //                    skipSelf = false;
        //                }
        //                if (waitUntilControl != null)
        //                {
        //                    if (waitUntilControl != dp)
        //                    {
        //                        return false;
        //                    }
        //                    waitUntilControl = null;
        //                }
        //                return dp.IsTabStop;
        //            };
        //        }
        //        Control control = rootObject.FindVisualChildByType<Control>(predicate);
        //        if (control != null)
        //        {
        //            return control.Focus();
        //        }
        //    }
        //    return false;
        //}

        //public static bool IsChildFocused(DependencyObject target)
        //{
        //    DependencyObject focusedElement = FocusManager.GetFocusedElement() as DependencyObject;
        //    if (focusedElement == null)
        //    {
        //        return false;
        //    }
        //    return (focusedElement.FindVisualParent(v => (v == target)) != null);
        //}

        //

        //public static Visibility CheckVisualVisibility(this DependencyObject visualElement)
        //{
        //    while (visualElement != null)
        //    {
        //        FrameworkElement element = visualElement as FrameworkElement;
        //        if (element != null)
        //        {
        //            if (element.Visibility == Visibility.Collapsed)
        //            {
        //                return Visibility.Collapsed;
        //            }
        //            if (element == Application.Current.RootVisual)
        //            {
        //                return Visibility.Visible;
        //            }
        //        }
        //        visualElement = VisualTreeHelper.GetParent(visualElement);
        //    }
        //    return Visibility.Collapsed;
        //}

        public static DependencyObject FindVisualChild(this DependencyObject visualElement,
                                                       Func<DependencyObject, bool> predicate)
        {
            return visualElement.FindVisualChild(predicate, false);
        }

        public static DependencyObject FindVisualChild(this DependencyObject visualElement,
                                                       Func<DependencyObject, bool> predicate, bool breathFirst)
        {
            if (breathFirst)
            {
                return FindVisualChildBreathFirst(visualElement, predicate);
            }
            return visualElement.FindVisualChildDepthFirst(predicate);
        }

        public static DependencyObject FindVisualChildBreathFirst(DependencyObject visualElement,
                                                                  Func<DependencyObject, bool> predicate)
        {
            var queue = new Queue<DependencyObject>();
            queue.Enqueue(visualElement);
            while (queue.Count > 0)
            {
                DependencyObject arg = queue.Dequeue();
                if (predicate(arg))
                {
                    return arg;
                }
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(arg); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(arg, i);
                    queue.Enqueue(child);
                }
            }
            return null;
        }

        public static T FindVisualChildByType<T>(this DependencyObject visualElement) where T : DependencyObject
        {
            return (visualElement.FindVisualChild(v => (v is T)) as T);
        }

        public static T FindVisualChildByType<T>(this DependencyObject visualElement, Func<T, bool> predicate)
            where T : DependencyObject
        {
            return visualElement.FindVisualChildByType(predicate, false);
        }

        public static T FindVisualChildByType<T>(this DependencyObject visualElement, Func<T, bool> predicate,
                                                 bool breathFirst) where T : DependencyObject
        {
            return (visualElement.FindVisualChild(delegate(DependencyObject v)
                                                      {
                                                          if (v is T)
                                                          {
                                                              return predicate((T) v);
                                                          }
                                                          return false;
                                                      }, breathFirst) as T);
        }

        private static DependencyObject FindVisualChildDepthFirst(this DependencyObject visualElement,
                                                                  Func<DependencyObject, bool> predicate)
        {
            if (predicate(visualElement))
            {
                return visualElement;
            }

            if (visualElement is ContentPresenter)
            {
                var content = visualElement as ContentPresenter;
                var temp = content.Content as FrameworkElement;
                object test = temp.FindName("rootFill");
                //var a = ((Panel)(content.ContentTemplate)).FindName("rootFill");


                return null;
            }
            else
            {
                int c = VisualTreeHelper.GetChildrenCount(visualElement);


                for (int i = 0; i < c; i++)
                {
                    DependencyObject a = VisualTreeHelper.GetChild(visualElement, i);
                    string test = ((FrameworkElement) a).Name;
                    DependencyObject obj3 = a.FindVisualChildDepthFirst(predicate);
                    if (obj3 != null)
                    {
                        return obj3;
                    }
                }
            }
            return null;
        }

        public static DependencyObject FindVisualParent(this DependencyObject visualElement,
                                                        Func<DependencyObject, bool> predicate)
        {
            while ((visualElement != null) && !predicate(visualElement))
            {
                DependencyObject parent = null;
                try
                {
                    parent = VisualTreeHelper.GetParent(visualElement);
                }
                catch (InvalidOperationException)
                {
                }
                if ((parent == null) && (visualElement is FrameworkElement))
                {
                    parent = ((FrameworkElement) visualElement).Parent;
                }
                visualElement = parent;
            }
            return visualElement;
        }

        public static T FindVisualParentByType<T>(this DependencyObject visualElement) where T : DependencyObject
        {
            return (T) visualElement.FindVisualParent(v => (v is T));
        }

        public static T FindVisualParentByType<T>(this DependencyObject visualElement, Func<T, bool> predicate)
            where T : DependencyObject
        {
            return (T) visualElement.FindVisualParent(delegate(DependencyObject v)
                                                          {
                                                              if (v is T)
                                                              {
                                                                  return predicate((T) v);
                                                              }
                                                              return false;
                                                          });
        }

        public static void VisitVisualChildren<T>(this DependencyObject visualElement, Action<T> visitor)
            where T : DependencyObject
        {
            if (visualElement is T)
            {
                visitor((T) visualElement);
            }
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visualElement); i++)
            {
                VisualTreeHelper.GetChild(visualElement, i).VisitVisualChildren(visitor);
            }
        }
    }
}